/*
 * Copyright 2014 HarryKim.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package opera.main;

import client.SkillFactory;
import client.inventory.MapleInventoryIdentifier;
import constants.ServerConstants;
import database.DatabaseConnection;
import handling.MapleServerHandler;
import handling.cashshop.CashShopServer;
import handling.channel.ChannelServer;
import handling.channel.MapleGuildRanking;
import handling.login.LoginInformationProvider;
import handling.login.LoginServer;
import handling.world.World;
import handling.world.family.MapleFamily;
import handling.world.guild.MapleGuild;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Properties;
import opera.constants.DatabaseConstants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import server.AutobanManager;
import server.CashItemFactory;
import server.MTSStorage;
import server.MapleCarnivalFactory;
import server.MapleItemInformationProvider;
import server.RankingWorker;
import server.ShutdownServer;
import server.SpeedRunner;
import server.Timer;
import server.events.MapleOxQuizFactory;
import server.life.MapleLifeFactory;
import server.life.MapleMonsterInformationProvider;
import server.life.MobSkillFactory;
import server.life.PlayerNPC;
import server.quest.MapleQuest;

/**
 *
 * @author HarryKim
 */
public class Main {

    private final long startTime;
    private static Main instance;
    private static final Logger Log = LoggerFactory.getLogger(Main.class);

    /* 제거할부분 시작 */
    public static boolean TUTORIAL_EXP_SYSTEM = false;
    public static boolean PC_BONUS_EXP_SYSTEM = false;
    public static boolean RAINBOW_WEEK_EXP_SYSTEM = false;
    public static boolean BOOM_UP_BONUS_EXP_SYSTEM = false;
    public static int TUTORIAL_EXP_SYSTEM_RATE;
    public static int PC_BONUS_EXP_SYSTEM_RATE;
    public static int RAINBOW_WEEK_EXP_SYSTEM_RATE;
    public static int BOOM_UP_BONUS_EXP_SYSTEM_RATE;

    static {
        try {
            FileInputStream exp = new FileInputStream("config/expsystem.properties");
            Properties expprobs = new Properties();
            expprobs.load(exp);
            exp.close();
            TUTORIAL_EXP_SYSTEM = expprobs.getProperty("TUTORIAL_EXP_SYSTEM").equals("true") ? true : false;
            PC_BONUS_EXP_SYSTEM = expprobs.getProperty("PC_BONUS_EXP_SYSTEM").equals("true") ? true : false;
            RAINBOW_WEEK_EXP_SYSTEM = expprobs.getProperty("RAINBOW_WEEK_EXP_SYSTEM").equals("true") ? true : false;
            BOOM_UP_BONUS_EXP_SYSTEM = expprobs.getProperty("BOOM_UP_BONUS_EXP_SYSTEM").equals("true") ? true : false;
            TUTORIAL_EXP_SYSTEM_RATE = Integer.parseInt(expprobs.getProperty("TUTORIAL_EXP_SYSTEM_RATE"));
            PC_BONUS_EXP_SYSTEM_RATE = Integer.parseInt(expprobs.getProperty("PC_BONUS_EXP_SYSTEM_RATE"));
            RAINBOW_WEEK_EXP_SYSTEM_RATE = Integer.parseInt(expprobs.getProperty("RAINBOW_WEEK_EXP_SYSTEM_RATE"));
            BOOM_UP_BONUS_EXP_SYSTEM_RATE = Integer.parseInt(expprobs.getProperty("BOOM_UP_BONUS_EXP_SYSTEM_RATE"));
        } catch (FileNotFoundException ex) {
            Log.error(null, ex);
        } catch (IOException ex) {
            Log.error(null, ex);
        }
    }
    /* 제거할부분 끝 */

    public Main() {
        this.startTime = System.currentTimeMillis();
    }

    private void init() {
        Log.info("Start initialize server data");
        DatabaseConstants.load();
        logoutAllAccounts();
        World.init();
        Timer.WorldTimer.getInstance().start();
        Timer.EtcTimer.getInstance().start();
        Timer.MapTimer.getInstance().start();
        Timer.CloneTimer.getInstance().start();
        Timer.EventTimer.getInstance().start();
        Timer.BuffTimer.getInstance().start();
        Timer.PingTimer.getInstance().start();
        MapleGuildRanking.getInstance().load();
        MapleGuild.loadAll(); //(this);
        MapleFamily.loadAll(); //(this);
        MapleLifeFactory.loadQuestCounts();
        MapleQuest.initQuests();
        MapleItemInformationProvider.getInstance().runEtc();
        MapleMonsterInformationProvider.getInstance().load();
        MapleItemInformationProvider.getInstance().runItems();
        SkillFactory.load();
        LoginInformationProvider.getInstance();
        MapleOxQuizFactory.getInstance();
        MapleCarnivalFactory.getInstance();
        MobSkillFactory.getInstance();
        SpeedRunner.loadSpeedRuns();
        MTSStorage.load();
        MapleInventoryIdentifier.getInstance();
        CashItemFactory.getInstance().initialize();
        MapleServerHandler.initiate();
    }

    private void start() {
        Log.info("Start load LoginServer");
        LoginServer.run_startup_configurations();
        Log.info("LoginServer is online");
        Log.info("Start load ChannelServer");
        ChannelServer.startChannel_Main();
        Log.info("ChannelServer is online");
        Log.info("Start load CashShopServer");
        CashShopServer.run_startup_configurations();
        Log.info("CashShopServer is online");

        Timer.CheatTimer.getInstance().register(AutobanManager.getInstance(), 60000);
        Runtime.getRuntime().addShutdownHook(new Thread(new ShutdownHook()));
        World.registerRespawn();
        ShutdownServer.registerMBean();
        ServerConstants.registerMBean();
        PlayerNPC.loadAll();
        MapleMonsterInformationProvider.getInstance().addExtra();
        LoginServer.setOn();
        RankingWorker.run();

        Log.info("Success to run MapleStory Server - {} seconds used", (System.currentTimeMillis() - startTime) / 1000);
    }

    private void logoutAllAccounts() {
        Connection con = null;
        PreparedStatement ps = null;
        try {
            con = DatabaseConnection.getConnection();
            ps = con.prepareStatement("UPDATE accounts SET loggedin = 0");
            ps.executeUpdate();
            Log.info("Success to logout all accounts");
        } catch (SQLException ex) {
            Log.error(null, ex);
        } finally {
            DatabaseConnection.close(ps, con);
        }
    }

    public static void main(String args[]) {
        instance = new Main();
        instance.init();
        instance.start();
    }

}
